Redis RDB和AOF持久化和数据恢复方式以及DB常用指令
RDB 快照持久化方式
RDB(Redis Database)在指定的时间间隔内,将内存中的全量数据生成一个二进制快照文件(dump.rdb)。类似于“拍照片”。核心配置参数:
1 | # 触发机制:save <秒> <修改次数> |
优点:恢复大数据集速度极快;文件紧凑,适合异地备份。
缺点:数据丢失风险大(上次备份到宕机之间的数据会丢失);fork 子进程时在大内存环境下可能导致瞬时卡顿。
AOF 追加日志持久化方式
AOF (Append Only File):记录每一个写操作指令,以追加的方式写入文件(appendonly.aof)。类似于“记账本”。核心配置参数:
1 | appendonly yes # 开启 AOF |
优点:数据最安全(最多丢失1秒数据);日志可读,可以手动修复(如误删后删掉 AOF 末尾的 FLUSHALL 指令)。
缺点:文件体积比 RDB 大;数据恢复速度慢(需要逐条回放指令)。
生产环境最佳实践
建议采用 “混合持久化” 策略:
策略:RDB + AOF 同时开启
混合模式:在 redis.conf 中设置
aof-use-rdb-preamble yes。AOF 重写时,文件前半部分是 RDB 格式(加载快),后半部分是增量指令(数据全)。异地备份:每天定时通过
cron脚本将 dump.rdb 拷贝到另一台服务器或云存储,防止物理机房故障。针对向量搜索(Valkey-Search)的优化:降低 AOF 重写频率:向量索引数据很大,频繁重写会造成磁盘 IO 飙升。建议将
auto-aof-rewrite-min-size(默认64mb)调大(如 512mb 或 1gb)。硬件级保障:
- 使用 SSD:Redis 持久化非常依赖磁盘的随机写入性能,SSD 是必须的。
- 预留内存:Linux 在 fork 时需要一定的内存余量。建议系统内存占用不要超过 70%,并设置
vm.overcommit_memory = 1。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# 在配置 Redis 持久化(尤其是 BGSAVE)时,vm.overcommit_memory = 1 是 Linux 内核参数中
# 最核心的一个。如果不设置它,在高负载下你的 Redis 经常会因为“内存不足”而备份失败,甚至崩溃。
# 简单来说,它是 Linux 处理内存分配的一种策略。
## 默认状态 (0):当 Redis 请求内存(比如 fork 子进程做快照)时,内核会进行启发式估算。如果它认为内存可能不够,就会拒绝该请求。
## 激进状态 (1):内核总是允许内存分配请求,直到物理内存真的用完。
## 设置成 1 后,内核会相信 Redis,直接允许 fork,从而保证持久化任务顺利开启。
# 临时生效(立即生效,重启失效)
echo 1 > /proc/sys/vm/overcommit_memory
# 或者
sysctl -w vm.overcommit_memory=1
# 永久生效(推荐)
vi /etc/sysctl.conf
# 在文件末尾添加一行
vm.overcommit_memory = 1
# 加载配置使其生效
sysctl -p
## 关闭linux内存大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 确保 net.core.somaxconn 至少设为 2048,匹配 Redis 的高并发需求。
net.core.somaxconn = 2048
误操作后怎么快速恢复!
比如执行了 FLUSHALL 后能否恢复数据,取决于你的 持久化配置(AOF 或 RDB)以及你反应的速度。请立即按照以下步骤进行“抢救”:
第一步:保持冷静,立即阻止任何新的写入:一旦发现误操作,不要重启 Redis(除非你没开 AOF),因为重启可能会触发新的持久化操作,覆盖掉现有的备份文件。
第二步:根据持久化方式选择恢复方案
场景 A:你开启了 AOF(最稳妥的恢复方式):
由于 AOF 记录的是每一条写命令,FLUSHALL 也会作为一个命令记在日志文件的末尾。你只需要把这一条删掉即可。
立即备份 AOF 文件:防止后续操作失误。
1
2
3
4
5
6
7
8
9# 如果是单纯的aof方式:
cp appendonly.aof appendonly.aof.bak
# 如果是混合rdb+aof方式:你会看到类似的至少三个文件:
# appendonly.aof.2.base.rdb:基础文件,这是混合持久化的核心,是上一次AOF重写时的内存全量快照(RDB格式)。
# appendonly.aof.2.incr.aof:增量文件,它记录了从上一次生成 .base.rdb 之后的所有写命令。你的 FLUSHALL 命令就写在这个文件的末尾。
# appendonly.aof.manifest:清单文件,告诉 Redis:当前的 AOF 由哪个 Base 文件和哪些 Incr 文件组成,以及它们的序列号(这里是 2),Redis 启动时会先读它。
mkdir /root/redis_backup
cp appendonly.aof.* /root/redis_backup/打开 AOF 文件进行编辑:
1
2
3vim appendonly.aof 或者 vim appendonly.aof.2.incr.aof
# 删除末尾的 FLUSHALL 命令:
# 滚动到文件最底部,你会看到类似 *1\r\n$8\r\nFLUSHALL 这样的记录。将其彻底删除。重启 Redis 实例: Redis 会重新读取修改后的 AOF 文件,数据就会像 “录像回放”一样全部回来(除了那条被你删掉的清空命令)。
场景 B:你只开启了 RDB:这种情况比较看运气,取决于 FLUSHALL 之后是否触发了新的 RDB 备份。
检查 dump.rdb 文件的时间戳: 如果 dump.rdb 的最后修改时间是在你执行 FLUSHALL 之前,那么你非常幸运。立即备份 dump.rdb 文件。
立即强制关闭 Redis 进程(不要执行正常的
shutdown,因为正常关机会尝试保存当前内存状态,即清空后的状态):1
2
3# 千万不要执行 redis-cli shutdown,因为正常退出可能再次触发持久化。
ps -ef | grep redis
kill -9 [Redis的PID]把备份的 dump.rdb 拷贝回数据目录。
重启 Redis,数据会恢复到上一次快照时的状态。
场景 C:你开启了混合持久化(AOF 头部是 RDB)
- 操作逻辑同 场景 A。依然是编辑 appendonly.aof,找到末尾的文本部分(AOF 混合模式下,文件末尾通常是正常的 AOF 文本指令),删掉 FLUSHALL 即可。
第三步:最后的 “核武器”——冷备份:如果你之前按照我建议的生产环境最佳实践,做了异地备份(比如每天凌晨拷贝一次
dump.rdb到另一台机器),那么你可以拿昨天的备份文件进行恢复。虽然会丢失今天的数据,但总好过全量丢失。最后:为了防止你的redis数据再次遭遇这种 “灭顶之灾”,请务必执行以下操作:
1
2
3
4
5
6
7
8
9# 重命名命令(最有效): 在 redis.conf 中加入:
rename-command FLUSHALL "OWLIAS_DANGEROUS_CLEAN_ALL"
rename-command FLUSHDB "" # 彻底禁用
rename-command CONFIG "OWLIAS_ADMIN_CONFIG"
# 权限控制: 确保生产环境的 Redis 开启了 requirepass 密码认证,避免脚本或外部工具误触。
# 开启 AOF
# 正如你看到的,AOF 是唯一能让你“反悔” 的后悔药。
异地定时备份脚本
第一步:
$ vim /root/scripts/redis_backup.sh
$ chmod +x /root/scripts/redis_backup.sh
1 |
|
第二步:配置 SSH 免密登录(核心)
在 Redis 服务器运行:
ssh-keygen -t rsa(一路回车)。拷贝公钥到备份服务器:
ssh-copy-id user@remote_ip。
第三步:设置定时任务 (Crontab)
执行 crontab -e,添加以下行,设置为每天凌晨 3:00 运行:
1 | 00 03 * * * /bin/bash /root/scripts/redis_backup.sh >> /var/log/redis_backup_cron.log 2>&1 |
DB相关的常用指令
1 | ## 数据库切换与基础管理 |
[注意]:
- Redis 集群模式下不支持多数据库,只能使用 DB 0,因此在集群环境下执行 save/bgsave/bgrewriteaof 等指令,本质上就是针对该节点唯一的 DB 0 进行持久化。
- 自动化胜过手动:在你的 redis.conf 中配置 save 规则(如 save 900 1)或开启 appendonly yes。Redis 会自动在后台调用 BGSAVE 或重写 AOF,不需要你手动执行。
- 如果你以后将应用部署到集群环境,备份时需要编写脚本,循环登录到每一个 Master 节点去执行 BGSAVE,并把每个节点的 dump.rdb 都拷贝出来。
- 除非是在停机维护或极端紧急情况下,否则永远不要在生产环境执行 SAVE。
关于 redis 的逻辑分库
在 Redis 的演进过程中,16 个逻辑数据库(DB 0-15)的设计其实是一个“历史遗留”且“备受争议”的功能。简单来说:分库设计是为了给单机模式下的用户提供一种简单的逻辑隔离手段,但在现代分布式架构(Cluster)中,这种设计被证明弊大于利。以下是分 16 个库的主要原因及其背后的逻辑:
为什么当初要分库?(设计初衷)
- 简单的环境隔离: 在早期开发中,大家习惯在同一个 Redis 实例上跑多个小项目。比如 DB 0 给 应用存用户 Session,DB 1 存临时缓存。这样可以避免 Key 名冲突,而不需要启动多个 Redis 进程。
快速清空逻辑块: 你可以执行 FLUSHDB 只清空当前数据库,而不影响其他数据库。这比用 “KEYS *” 匹配前缀再删除要快得多。
管理便利性: 对于运维来说,管理一个端口(6379)下的多个 DB,比维护 16 个不同端口的 Redis 实例要省事(省内存、省进程管理)。
为什么集群模式(Cluster)却抛弃了它?
当你从单机升级到集群时,Redis 强制只能使用 DB 0。这是因为:
- 代理与路由的复杂性: Redis 集群的核心是 Hash Slot(哈希槽)。数据分片是根据 Key 计算的。如果允许 16 个库,那么路由指令时不仅要看 Key 在哪个节点,还要看它在哪个库,这会极大增加集群代理和客户端的实现难度。
- 资源竞争无法隔离: 虽然库号不同,但它们共享同一个 CPU 核心和 IO 线程。如果 DB 0 在做极其复杂的向量搜索(Valkey-Search),DB 1 一样会卡住。这种 “伪隔离” 在追求高并发的集群环境下意义不大。
- 官方的态度: Redis 之父 antirez 曾公开表示,Redis 的多数据库设计是他最大的设计失误之一。他更倾向于推荐用户 “一个实例只跑一个业务”。
生产环境实践:
- 强烈建议你养成 “只用 DB 0” 的习惯!
- 使用命名空间:在代码里给 Key 加前缀,如 “Search:Index:…”、 “Cache:Temp:…”。
- 在 Redis 中使用冒号(
:)作为分隔符来构建 Key 的前缀,是社区公认的最佳实践。这种做法本质上是在逻辑上模拟关系型数据库中的 “表” 或 “模式” 概念。 - 数据的逻辑隔离与分类:注意是逻辑隔离而非物理隔离。如果是集群模式,Redis 使用
CRC16 算法对 Key 进行哈希,然后将其分配到16384 个“哈希槽”(Hash Slots)中。Search:Index:1 和 Cache:Temp:1 的哈希结果几乎肯定不同,因此它们很可能会被分配到不同的物理主机上。但是同一种前缀的数据(如 Search:1 和 Search:2)也会因为哈希值不同而散落在不同的主机上。如果你希望特定前缀的数据必须堆放在同一个主机上(为了执行多 Key 事务),你可以使用花括号:{Search}:Index:1、{Search}:Index:2这种形式。Redis 只会对{}里的内容进行哈希。这样,所有以 {Search} 开头的 Key 都会进入同一个哈希槽,存储在同一台主机上。 - 防止 Key 冲突:在大型项目或微服务架构中,不同的开发者或模块可能会起相同的名字。而使用命名空间能够有效解决这一问题。
- 便于批量管理与分析:Redis 的一些命令和工具深度依赖前缀匹配。比如,使用 SCAN 命令配合 “MATCH Search:*” 可以快速找到特定模块的所有Key,而不影响生产环境性能。使用分析工具(如 redis-rdb-tools)时,可以按前缀统计各业务模块的内存占用情况。使用 redis-cli 或图形化管理工具(如 Redis Insight)时,前缀会让 Key 自动呈现为树状结构。
- 权限控制(ACL):Redis 7.0 可以通过 ACL 设置某个账号只能访问带有特定前缀的 Key,这比分库更安全、更强大。
- 在 Redis 中使用冒号(